﻿Imports System.Text.RegularExpressions

Public NotInheritable Class TableAttributeFactory

    Private Shared _factory As TableAttributeFactory = Nothing
    ''' <summary>
    ''' 略称辞書
    ''' </summary>
    ''' <remarks>
    ''' #78　テーブル、列名の略称辞書を作る
    ''' </remarks>
    <Obsolete("StringFormConverterクラスで管理されるよう変更")>
    Public Shared Abbreviations As Dictionary(Of String, String) = StringFormConverter.Abbreviations '#97　MySQL対応

    Public Shared Function Instance() As TableAttributeFactory
        '#97　MySQL対応
        'DBMSごとの生成クラスを統合。
        If _factory Is Nothing Then
            _factory = New TableAttributeFactory
        End If
        Return _factory
    End Function

    ''' <summary>
    ''' 表属性を取得します。
    ''' </summary>
    ''' <param name="t"></param>
    ''' <param name="callback">生成したインスタンスの受け取り</param>
    ''' <remarks></remarks>
    Public Function Create(ByVal t As Type, callback As Action(Of TableAttribute)) As TableAttribute
        '指定された属性
        Dim atr As TableAttribute = Me.CreateTable(t)

        'カスケード処理、列追加処理をする前に、先にキャッシュ登録してもらうため、この時点で返却します。
        If callback IsNot Nothing Then callback.Invoke(atr)

        '通常列の追加
        For Each item In NormalColumnAttributeFactory.Instance.Create(atr)
            atr.Columns.Add(item)
        Next

        '基底列の追加
        For Each item In SuperRelationFactory.Instance.Create(atr)
            atr.SuperRelations.Add(item)
            '#96　基底クラスとのリレーションするための列は、基底リレーションクラスに登録されているものを使用します。
            '基底クラスリレーションを列として追加
            atr.Columns.Add(item.MyColumn)
        Next

        '親列の追加
        For Each item In ParentRelationColumnAttributeFactory.Instance.Create(atr)
            atr.Columns.Add(item)
        Next

        '子関連を取得
        For Each item In ChildRelationFactory.Instance.Create(atr)
            atr.ChildRelations.Add(item)
        Next

        Return atr
    End Function

    Private Function CreateTable(t As Type) As TableAttribute
        '指定された属性
        Dim manual As TableAttribute = Me.CreateTable_Manual(t)

        '制約上の属性
        Dim master As TableAttribute = Me.CreateTable_Master(t)

        If manual Is Nothing Then
            '指定がない場合は、制約上の属性をそのまま返します。
            manual = master
        Else
            '指定がされている場合、省略した値を制約から補てんします。
            manual.ModelType = master.ModelType
            If String.IsNullOrEmpty(manual.ModelTypeAbbreviation) Then manual.ModelTypeAbbreviation = master.ModelTypeAbbreviation
            If String.IsNullOrEmpty(manual.TableName) Then manual.TableName = master.TableName
            If String.IsNullOrEmpty(manual.TableNamespace) Then manual.TableNamespace = master.TableNamespace
        End If

        Return manual
    End Function

    ''' <summary>
    ''' 指定された表属性を取得します。
    ''' </summary>
    ''' <param name="t"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CreateTable_Manual(ByVal t As Type) As TableAttribute
        Return AttributeReader.Read(Of TableAttribute)(t).FirstOrDefault
    End Function

    ''' <summary>
    ''' 制約上の表属性を取得します
    ''' </summary>
    ''' <param name="t"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CreateTable_Master(ByVal t As Type) As TableAttribute
        '#97　MySQL対応
        Dim cnv = StringFormConverter.Instance
        Dim name As String = cnv.ToTable(t)

        '#79　基底クラスにマッピングされているテーブルを読み込んだときに継承を再現する
        Dim s As String = String.Empty
        For Each item In (From el In t.Name Where Char.IsUpper(el))
            s &= item
        Next

        Dim atr As New TableAttribute(name) With {.ModelType = t, .TableNamespace = cnv.ToNameSpace(t), .ModelTypeAbbreviation = s}

        Return atr
    End Function

End Class
